//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/parallel/atomics.h"
#include "sagittarius/mem/span.h"
#include "sagittarius/io/io.h"

//small object allocation
void* smo_allocs_b(sg_span* s) {
    void *obj;
    freenode_t n, q, *pnext;
    size_t bs = s->bs;
    size_t headeroff = bs - 4;
    
    WLSEMA(s->sema);
    
    n = s->freenode;
    if(n == SG_FREENODE_EXH)
        return NULL;
    pnext = (freenode_t*)((uint8*)s->addr + n*bs + headeroff); //TODO: lea
    q = s->instnode;
    if(n == q) {
        s->freenode = s->instnode = SG_FREENODE_EXH;
    } else
        s->freenode = *pnext;
    
    obj = (uint8*)s->addr + n*bs;
    *(freenode_t*)((uint8*)obj+headeroff) |= 0x80000000; //distinguishes alloc'd objs from freed ones
    
    WUSEMA(s->sema);
    
    return obj;
}

int smo_frees(sg_span* s, void* obj) {
    //TODO: init memory to bit pattern before calling this func
    //so we can prevent inappropriate/duplicate frees (sort of done)
    freenode_t n, q, *pnext;
    intptr_t boff = (uint8*)obj - (uint8*)s->addr;
    size_t bs = s->bs;
    freenode_t off = (freenode_t)(boff / bs);
    size_t headeroff = bs - 4;
    
    AZ(boff % s->bs, "Offset misaligned");
    
    AN(*(freenode_t*)((uint8*)obj+headeroff) & 0x80000000, "Free applied to nonowned memory. Possible double use of free"); //TODO: return error
    *(freenode_t*)((uint8*)obj+headeroff) = SG_FREENODE_EXH;
    
    WLSEMA(s->sema);
    
    n = s->freenode;
    q = s->instnode;
    //starting from empty queue
    if(q == SG_FREENODE_EXH && n == SG_FREENODE_EXH) {
        s->freenode = off;
    }
    
    //usual case
    pnext = (freenode_t*)((uint8*)s->addr + q*bs + headeroff);
    
    AT(*pnext == SG_FREENODE_EXH, "Link invariant failed");
    *pnext = off;
    s->instnode = off;
    
    WUSEMA(s->sema);
    
    return 0;
}
